package com.xd.core.task.controller;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateUnit;
import cn.hutool.core.date.DateUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.xd.common.constant.SysConstant;
import com.xd.core.api.dto.SinglePayDto;
import com.xd.core.business.entity.RepaymentSchedule;
import com.xd.core.business.entity.Surrenderinfo;
import com.xd.core.business.mapper.CarCreditMapper;
import com.xd.core.business.mapper.GuaranteeSlipMapper;
import com.xd.core.business.mapper.RepaymentScheduleMapper;
import com.xd.core.business.mapper.SurrenderinfoMapper;
import com.xd.core.debt.entity.Debt;
import com.xd.core.debt.mapper.DebtMapper;
import com.xd.core.mission.mapper.MissionCenterInfoMapper;
import com.xd.core.note.IAsyncService;
import com.xd.core.system.controller.SysPermissionController;
import com.xd.core.system.service.FileService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.Calendar;
import java.util.Comparator;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

@Slf4j
@Component
public class TaskController {
    @Value("${spring.profiles.active}")
    private String active;
    @Autowired
    private RepaymentScheduleMapper repaymentScheduleMapper;
    @Autowired
    private DebtMapper debtMapper;
    @Autowired
    private SurrenderinfoMapper surrenderinfoMapper;
    @Autowired
    private IAsyncService asyncService;
    @Autowired
    private MissionCenterInfoMapper missionCenterInfoMapper;
    @Autowired
    private FileService fileService;
    @Autowired
    private CarCreditMapper carCreditMapper;
    @Autowired
    private GuaranteeSlipMapper guaranteeSlipMapper;
    //提前还款
    public static final String PAID = "3";
    //提前结清
    public static final String OVERDUE_PAID = "4";
    @Autowired
    private SysPermissionController sysPermissionController;


    /*
     * 自动代扣 上午10点 下午4点执行
     * 1.还款计划表——————本期还款计划有逾期的先还逾期 未申请提前还款 还款方式为线上代扣
     * 加锁 跑人任务时  不能手动代扣以及线下还款
     * */
//    @Scheduled(cron = "0 0 10,16 * * ?")
    /*@Transactional(rollbackFor = Exception.class)
    public void deductionOrder() throws Exception {
        log.info("<--------------自动扣款当期定时任务启动-------------->");
        long start = System.currentTimeMillis();
        //查询本期未还  有逾期先还逾期
        List<SinglePayDto> l3 = debtMapper.selectSinglePayList();
        for (SinglePayDto s3 : l3) {
            String lockKey = REPAY_LOCK_KEY + s3.getOrderId();
            RLock lock = redissonClient.getLock(lockKey);
            try {
                lock.lock(60*5,TimeUnit.SECONDS);
                //查询是否有申请中的代扣
                RepaymentOrderInfo re = repaymentOrderInfoMapper.selectOne(new LambdaQueryWrapper<RepaymentOrderInfo>().eq(RepaymentOrderInfo::getOrderId, s3.getOrderId()).eq(RepaymentOrderInfo::getPayStatus, "1"));
                if (re != null)
                    continue;
                //插入订单表
                String deptOrder = OrderNumUtil.getRepayOrder(s3.getCompanyId());
                RepaymentOrderInfo repaymentOrderInfo = new RepaymentOrderInfo();
                repaymentOrderInfo.setOrderId(s3.getOrderId());
                repaymentOrderInfo.setDebtId(s3.getDebtId());
                repaymentOrderInfo.setOrderNo(deptOrder);
                repaymentOrderInfo.setType(SysConstant.DEDUCT_MONEY_TYPE_ONE);
                repaymentOrderInfo.setAmount(Integer.parseInt(s3.getAmount()));
                repaymentOrderInfo.setCompanyId(s3.getCompanyId());
                repaymentOrderInfo.setRepayName(s3.getRepayName());
                repaymentOrderInfo.setRepayAccount(s3.getRepayAccount());
                repaymentOrderInfo.setRepayBank(s3.getRepayBank());
                //插入订单
                repaymentOrderInfoMapper.insert(repaymentOrderInfo);

                s3.setOrderNo(deptOrder);
                dlApiService.singlePay(s3);
            }catch (Exception e){
              throw new XkdException(e.getMessage());
            }finally {
                // 确保锁的释放在事务提交之后
                TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization() {
                    @Override
                    public void afterCompletion(int status) {
                        if (lock.isHeldByCurrentThread()) {
                            lock.unlock();
                            if (status == TransactionSynchronization.STATUS_COMMITTED) {//成功
                                log.info("事务已提交，自动扣款当期定时任务释放锁，订单ID: {}", s3.getDebtId());
                            } else {//回滚
                                log.warn("事务已回滚，自动扣款当期定时任务释放锁，订单ID: {}", s3.getDebtId());
                            }
                        }
                    }
                });
            }
        }
        log.info("<--------------自动扣款当期定时任务执行完毕,耗时:" + (System.currentTimeMillis() - start) + "毫秒-------------->");
    }
*/
    @Scheduled(cron = "0 0 10,16 * * ?")
//    @Scheduled(cron = "0 10 10,16 * * ?")
    public void deductionOrder() throws Exception {
        if (!"prd".equals(active))
            return;
        log.info("<--------------自动扣款当期定时任务启动-------------->");
        long start = System.currentTimeMillis();
        //查询本期未还  有逾期先还逾期
        List<SinglePayDto> l3 = debtMapper.selectSinglePayList();
        for (SinglePayDto s3 : l3) {
            asyncService.deductionOrder(s3);
        }
        log.info("<--------------自动扣款当期定时任务执行完毕,耗时:" + (System.currentTimeMillis() - start) + "毫秒-------------->");
    }

    @Scheduled(cron = "0 0 10,16 * * ?")
    @Transactional(rollbackFor = Exception.class)
    public void deductionDebt() throws Exception {
        if (!"prd".equals(active))
            return;
        log.info("<--------------自动扣款提前还款定时任务启动-------------->");
        //查询提前还款并且选择代扣的
        List<SinglePayDto> l4 = debtMapper.selectEarlyPay();
        long start = System.currentTimeMillis();
        for (SinglePayDto s4 : l4) {
            asyncService.deductionDebt(s4);
        }
        log.info("<--------------自动扣款提前还款定时任务执行完毕,耗时:" + (System.currentTimeMillis() - start) + "毫秒-------------->");
    }

    //清空7天前的导出文件
    @Scheduled(cron = "${scheduled.twelve}")
    @Transactional
    public void truncateMissionCenter() {
        log.info("<--------------清除导出文件定时任务启动-------------->");
        long start = System.currentTimeMillis();
        List<String> list = missionCenterInfoMapper.selectTruncateMissionCenter();
        missionCenterInfoMapper.truncateMissionCenter();
        for (String path : list) {
            fileService.fileRemove(path);
        }
        log.info("<--------------清除导出文件定时任务执行完毕,耗时:{}毫秒-------------->", System.currentTimeMillis() - start);
    }

    /*
     * 自动代扣 上午10点 下午4点执行
     * 2.债权表——————提前还款选择代扣的
     * 加锁 跑任务时  不能手动代扣以及线下还款
     * */
    //    @Scheduled(cron = "0 0 10,16 * * ?")
/*
    @Transactional(rollbackFor = Exception.class)
    public void deductionDebt() throws Exception {
        log.info("<--------------自动扣款提前还款定时任务启动-------------->");
        //查询提前还款并且选择代扣的
        List<SinglePayDto> l4 = debtMapper.selectEarlyPay();
        long start = System.currentTimeMillis();
        for (SinglePayDto s4 : l4) {
            String lockKey = DEBT_LOCK_KEY + s4.getDebtId();
            RLock lock = redissonClient.getLock(lockKey);
            try {
                lock.lock(60*5,TimeUnit.SECONDS);
                //插入订单表
                String deptOrder = OrderNumUtil.getRepayOrder(s4.getCompanyId());
                RepaymentOrderInfo repaymentOrderInfo = new RepaymentOrderInfo();
                repaymentOrderInfo.setDebtId(s4.getDebtId());
                repaymentOrderInfo.setOrderNo(deptOrder);
                repaymentOrderInfo.setType(SysConstant.DEDUCT_MONEY_TYPE_FOUR);
                repaymentOrderInfo.setAmount(Integer.parseInt(s4.getAmount()));
                repaymentOrderInfo.setCompanyId(s4.getCompanyId());
                repaymentOrderInfo.setRepayName(s4.getRepayName());
                repaymentOrderInfo.setRepayAccount(s4.getRepayAccount());
                //插入订单
                repaymentOrderInfoMapper.insert(repaymentOrderInfo);
                s4.setOrderNo(deptOrder);
                dlApiService.singlePay(s4);
            } finally {
                // 确保锁的释放在事务提交之后
                TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization() {
                    @Override
                    public void afterCompletion(int status) {
                        lock.unlock();
                        if (status == TransactionSynchronization.STATUS_COMMITTED) {
                            log.info("事务已提交，自动扣款提前还款定时任务释放锁，债务ID: {}", s4.getDebtId());
                        } else {
                            log.warn("事务已回滚，自动扣款提前还款定时任务释放锁，债务ID: {}", s4.getDebtId());
                        }
                    }
                });
            }

        }
        log.info("<--------------自动扣款提前还款定时任务执行完毕,耗时:" + (System.currentTimeMillis() - start) + "毫秒-------------->");
    }
*/

    /**
     * 保单贷每天下午6点逾期利息
     */
    @Transactional(rollbackFor = Exception.class)
    @Scheduled(cron = "0 0 18 * * ?")
    public void calculateOverdueInterestInsurance() {
        log.info("<--------------18点计算罚息定时任务启动-------------->");
        long start = System.currentTimeMillis();
        // 获取前一天的日期
        BigDecimal fiveRate = new BigDecimal(36).divide(new BigDecimal(36000),2,RoundingMode.HALF_UP);
        BigDecimal sixRate = new BigDecimal(24).divide(new BigDecimal(36000),10,RoundingMode.HALF_UP);
        Calendar calendar = Calendar.getInstance();
        Date today = calendar.getTime();
        calendar.add(Calendar.DAY_OF_MONTH, -1);
        Date yesterday = calendar.getTime();
        //获取保单贷逾期的还款计划表
        List<RepaymentSchedule> repaymentSchedules= repaymentScheduleMapper.selectInsurance(today);

        if (CollectionUtil.isEmpty(repaymentSchedules)) {
            log.info("没有逾期的账单");
            return;
        }
        // 按 repaymentDate 按还款日期升序只取最早的一起逾期
        List<RepaymentSchedule> distinctSchedules = repaymentSchedules.stream()
                .sorted(Comparator.comparing(RepaymentSchedule::getRepaymentDate))
                .collect(Collectors.toMap(
                        RepaymentSchedule::getIncomingId,
                        schedule -> schedule,
                        (existing, replacement) -> existing // 保留先出现的元素（按 repaymentDate 排序）
                ))
                .values()
                .stream()
                .collect(Collectors.toList());

        List<Integer> outIds = distinctSchedules.stream().map(RepaymentSchedule::getOutId).collect(Collectors.toList());
        List<Debt> debts = debtMapper.selectInsuranceList(outIds);

        BigDecimal overdueInterest =BigDecimal.ZERO;
        for (RepaymentSchedule repaymentSchedule : distinctSchedules) {
            for (Debt debt : debts) {
                if (repaymentSchedule.getOutId().equals(debt.getOutId())) {
                    Date repaymentDate = repaymentSchedule.getRepaymentDate();
                    int overDueDay = (int) DateUtil.between(repaymentDate, yesterday, DateUnit.DAY);
                    if (overDueDay <= 5) {
                        overdueInterest  = repaymentSchedule.getAmount().multiply(fiveRate).multiply(new BigDecimal(overDueDay));
                    } else {
                        BigDecimal fiveDay = repaymentSchedule.getAmount().multiply(fiveRate).multiply(new BigDecimal(5));
                        overdueInterest = debt.getRemainingShouldRepayPrincipal().multiply(sixRate).multiply(new BigDecimal(overDueDay - 5)).add(fiveDay);
                    }
                    debt.setOverdueInterest(overdueInterest);
                    debt.setOverdueDays(overDueDay);
                }
            }
        }
        if (CollectionUtil.isNotEmpty(debts)){
            debtMapper.updateInterestAndPrincipal(debts);
        }
        repaymentScheduleMapper.updateStatusAndOverdue(repaymentSchedules);
        log.info("<--------------18点计算罚息定时任务执行完毕,耗时:" + (System.currentTimeMillis() - start) + "毫秒-------------->");
    }


    @Transactional(rollbackFor = Exception.class)
    @Scheduled(cron = "0 0 0 * * ?")
    public void calculateOverdueInterestAndDays() {
        log.info("<--------------12点计算罚息定时任务启动-------------->");
        long start = System.currentTimeMillis();
        // 获取前一天的日期
        Calendar calendar = Calendar.getInstance();
        calendar.add(Calendar.DAY_OF_MONTH, -1);
        Date yesterday = calendar.getTime();

        //获取所有逾期的还款计划表按还款日期升序
        List<RepaymentSchedule> repaymentSchedules= repaymentScheduleMapper.select(yesterday);
        if (CollectionUtil.isEmpty(repaymentSchedules)) {
            log.info("没有逾期的账单");
            return;
        }
        List<Integer> outIds = repaymentSchedules.stream().map(RepaymentSchedule::getOutId).collect(Collectors.toList());

        LambdaQueryWrapper<Debt> wrapper1 = new LambdaQueryWrapper<Debt>().in(Debt::getOutId, outIds);
        List<Debt> debts = debtMapper.selectList(wrapper1);


        for (Debt debt : debts) {
            for (RepaymentSchedule repaymentSchedule : repaymentSchedules) {
                if (repaymentSchedule.getOutId().equals(debt.getOutId())) {
                    BigDecimal overdueInterest;
                    Integer overdueDays = debt.getOverdueDays();
                    //修改逾期天数
                    overdueDays += 1;
                    debt.setOverdueDays(overdueDays);
                    BigDecimal divide = BigDecimal.valueOf(overdueDays).divide(BigDecimal.valueOf(30), 10, RoundingMode.HALF_UP);
                    //计算逾期利息
                    BigDecimal remainingShouldRepayPrincipal = debt.getRemainingShouldRepayPrincipal();
                    overdueInterest = remainingShouldRepayPrincipal.multiply(BigDecimal.valueOf(0.02)).multiply(divide).setScale(2, RoundingMode.HALF_UP);
                    //计算罚息
                    BigDecimal defaultInterestTodo = repaymentSchedule.getInterestTodo().multiply(BigDecimal.valueOf(0.02)).multiply(divide).setScale(2, RoundingMode.HALF_UP);
                    debt.setOverdueInterest(overdueInterest);
                    debt.setDefaultInterestTodo(defaultInterestTodo);
                    break;
                }
            }
        }
        if (CollectionUtil.isNotEmpty(debts)){
            debtMapper.updateInterestAndPrincipal(debts);
        }
        //如果为提前还款或提前结清，不修改状态
        List<RepaymentSchedule> collect = repaymentSchedules.stream().filter(rs -> !rs.getStatus().equals(PAID) && !rs.getStatus().equals(OVERDUE_PAID)).collect(Collectors.toList());
        repaymentScheduleMapper.updateStatusAndOverdue(collect);
        log.info("<--------------12点计算罚息定时任务执行完毕,耗时:" + (System.currentTimeMillis() - start) + "毫秒-------------->");
    }

    /**
     * 清空扣款次数
     */
    @Scheduled(cron = "0 0 0 * * ?")
    public void clearRepayTimes() {
        log.info("<--------------12点清零扣款定时任务启动-------------->");
        long start = System.currentTimeMillis();
        repaymentScheduleMapper.clearRepayTimes();

        log.info("<--------------12点清零扣款定时任务执行完毕,耗时:" + (System.currentTimeMillis() - start) + "毫秒-------------->");
    }

    @Scheduled(cron = "0 0 0 * * ?")
    public void clearWithholdingTimes() {
        log.info("<--------------12点清零代扣次数定时任务启动-------------->");
        long start = System.currentTimeMillis();
        debtMapper.clearRepayTimes();

        log.info("<--------------12点清零代扣次数定时任务执行完毕,耗时:" + (System.currentTimeMillis() - start) + "毫秒-------------->");
    }

    @Scheduled(cron = "0 0 0 * * ?")
    public void debtAutoRelease() {
        log.info("<--------------12点扫描债权释放时间定时任务启动-------------->");
        long start = System.currentTimeMillis();
        //获取所有待释放的债权
        List<Integer> debtIds = debtMapper.debtAutoRelease();
        //释放到期的债权
        if (CollectionUtil.isNotEmpty(debtIds)) {
            debtMapper.batchUpdateDebt(debtIds);
        }
        log.info("<--------------12点扫描债权释放时间定时任务执行完毕,耗时:" + (System.currentTimeMillis() - start) + "毫秒-------------->");
    }


    @Scheduled(cron = "0 0 0 * * ?")
    public void underProtectionStatus() {
        log.info("<--------------12点扫描保单是否在保定时任务启动-------------->");
        long start = System.currentTimeMillis();
        //根据车牌号获取已超过商业保险结束日期并且状态不为已失效的保单
        List<Integer> policyId= carCreditMapper.getAllGuaranteeSlip();
        if(CollectionUtil.isNotEmpty(policyId)){
            //根据保单id批量修改保单的状态为已失效
            guaranteeSlipMapper.batcUpdateStatus(policyId);
        }
        log.info("<--------------12点扫描保单是否在保定时任务执行完毕,耗时:" + (System.currentTimeMillis() - start) + "毫秒-------------->");
    }
}
